;;; This defines the coordinate system used by the engine
;;; We will represent vectors with any sequence, but prefer CL vectors.
;;; Maybe factor this out into a library and use it for sunsnail too?
(defun v+ (v1 &rest vs)
  (apply 'map (type-of v1) '+ v1 vs))

(defun k*v (k v)
  (map (type-of v) (lambda (k1) (* k1 k)) v))
(defun v*k (v k) ; convenience
  (k*v k v))

(defun v- (v1 &rest vs)
  (v+ v1 (k*v -1 (apply 'v+ vs))))

; not vector operations, but very convenient
(defun 1/v (v)
  "Component-wise multiplicative inverse
   (1/v #(a b c d)) ==> #(1/a 1/b 1/c 1/d)"
  (map (type-of v) '/ v))
(defun scale-by (v1 &rest vs)
  "Component-wise multiplication
   (scale-by #(a b c) #(d e f)) ==> #(a*d b*e c*f)"
  (apply 'map (type-of v1) '* v1 vs))


;;; Now define functions for converting between SDL-space and game-space

(defparameter *tile-size* #(10 10) "Size of a game tile in SDL pixels")
; Might want to make these functions or symbol-macros
(defparameter *tile-x* (aref *tile-size* 0))
(defparameter *tile-y* (aref *tile-size* 1))

(defun seq->point (seq)
  "Convert a two-length sequence to an SDL point"
  (assert (= 2 (length seq)))
  (sdl:point :x (elt seq 0) :y (elt seq 1)))
(defun point->seq (point)
  "Convert an SDL point to a two-length sequence (in this case a vector)"
  (multiple-value-call 'vector (sdl:point-* point)))

(defun scale-to-sdl (seq)
  "Transform game coordinates (as a sequence) to SDL coordinates (as a sequence)"
  (scale-by seq *tile-size*))
(defun scale-to-game (seq)
  "Transform SDL coordinates (as a sequence) to game coordinates (as a sequence)"
  (scale-by seq (1/v *tile-size*)))

(defun game->sdl (seq)
  "Tranfsorm game coordinates to SDL coordinates and return an sdl:point"
  (seq->point (scale-to-sdl seq)))

(defun sdl->game (point)
  "Transform SDL coordinates to game coordinates. Take an sdl:point and return a sequence."
  (scale-to-game (point->seq point)))

(defun game->sdlrect (seq)
  "Like game->sdl, but return an sdl:rectangle corresponding to the entire grid space"
  (sdl:rectangle-from-edges (game->sdl seq)
			    (seq->point (v+ (scale-to-sdl point) *tile-size*))))
(defun game->drawloc (seq)
  "Transform game coordinates to SDL, but add #(1 1) before transforming the resulting sequence to an sdl:point."
  (seq->point (v+ #(1 1) (scale-to-sdl seq))))


